package com.condroid;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.regex.Pattern;

import android.os.Handler;
import android.os.Message;
import android.telephony.SmsManager;

/**
 * This class is used for detecting the incoming data
 * in the InputStream and send it to user.
 * @author JUN GAO
 * Condroid Summer CSD 2011 - KTH
 */
public class InUartThread extends Thread {
	private InputStream in;
	private byte[] buffer = new byte[512];
	private boolean finished = false;
	private int availableBytes;
	private Handler handler;
	private String phoneNo;
	private Pattern pattern = Pattern.compile("\\W");
	private ConstantData.ControlType type;//specify who invoked this thread(i.e. console module, SMS module etc.)
	
	{
		java.util.Arrays.fill(buffer, (byte) 0);
	}
	
	/**
	 * Used only for SMS or dialing module.
	 * @param in The InputStream to detect incoming data.
	 * @param phoneNo The phone number which should send received info to
	 * @param type The type of invoke class. for this method should only be
	 * SMS or CALL.
	 */
	public InUartThread(InputStream in, String phoneNo, ConstantData.ControlType type){
		this.in = in;
		this.phoneNo = phoneNo;
		this.type = type;
	}
	
	/**
	 * Used only for console or internet module.
	 * @param in The InputStream to detect incoming data.
	 * @param h The handler which used to send received info to
	 * @param type The type of invoke class. for this method should only be
	 * CONSOLE or INTERNET.
	 */
	public InUartThread(InputStream in, Handler h, ConstantData.ControlType type){
		this.in = in;
		this.handler = h;
		this.type = type;
	}
	
	/**
	 * Detecting loop
	 */
	@Override
	public void run() {
		super.run();
		switch (type) {
		case CONSOLE:
			consoleLoop();
			break;
		case CALL:
		case SMS:
			smsLoop();
			break;
		case INTERNET:
			// TODO Internet loop could be the same with console
			break;
		default:
			break;
		}
	}
	
	private void consoleLoop(){
		while(!finished && in != null){
			try{
				availableBytes = in.available();
				if(availableBytes > 0){
					in.read(buffer, 0, availableBytes);
					String s = new String(buffer).trim();
					send(s);
					java.util.Arrays.fill(buffer, (byte) 0);
				}
				sleep(SLEEPTIME);
			}catch(IOException ioe){
				errorReport("InUartThread run() IOException!" + ConstantData.NEWLINE);
			}catch(InterruptedException ie){
				errorReport("InUartThread sleep()InterrupteException!" + ConstantData.NEWLINE);
			}
		}
	}
	
	private void smsLoop() {
		StringBuilder sBuf = new StringBuilder();
		long timeOfFirstByte = Long.MAX_VALUE;
		boolean isEmpty = true;

		while (!finished && in != null) {
			try {
				availableBytes = in.available();
				if (availableBytes > 0) {
					in.read(buffer, 0, availableBytes);
					String s = new String(buffer).trim();
					sBuf.append(s);
					java.util.Arrays.fill(buffer, (byte) 0);
					if (isEmpty) {
						timeOfFirstByte = new Date().getTime();
						isEmpty = false;
					}
				}

				if (!isEmpty && new Date().getTime() - timeOfFirstByte > WAITINGTIME) {
					send(phoneNo, sBuf.toString());
					sBuf = new StringBuilder();
					isEmpty = true;
				}

				sleep(SLEEPTIME);
			} catch (IOException ioe) {
				errorReport(phoneNo, "InUartThread run() IOException!"
						+ ConstantData.NEWLINE);
			} catch (InterruptedException ie) {
				errorReport(phoneNo, "InUartThread sleep()InterrupteException!"
						+ ConstantData.NEWLINE);
			}
		}
		
		send(phoneNo, "inUartThread ended!");
	}
	
	private void errorReport(String s) {
			send(s);
	}
	
	private void errorReport(String phoneNo, String s){
		send(phoneNo, s);
	}
	
	private void send(String s) {
		if (handler != null) {
			Message m = Message.obtain();
			m.setTarget(handler);
			m.obj = s;
			m.sendToTarget();
		}
	}
	
	private void send(String phoneNo, String s){
		SmsManager sms = SmsManager.getDefault();
		ArrayList<String> al = sms.divideMessage(s);
		sms.sendMultipartTextMessage(phoneNo, ConstantData.phoneNo, al, null, null);
	}
	
	/**
	 * Invoke this method to finish this thread and stop detection.
	 */
	public synchronized void finish(){
		finished = true;
		try {
			in.close();
		} catch (IOException e) {
			errorReport("InUartThread close() IOException!" + ConstantData.NEWLINE);
		}
	}
	
//	public void setSleepTime(int sleepTime){
//		this.sleepTime = sleepTime;
//	}
	
	private final int SLEEPTIME = 50;
	private final int WAITINGTIME = 3000;
	private final int MESSAGELENGTH = 20;
}
